﻿using System.Reflection;
using Autofac;
using WT.OpenIddict.Domain.Services;
using WT.OpenIddict.Domain.Shared.LifeTime;
using WT.OpenIddict.EntityFrameWorkCore;
using WT.OpenIddict.Repository.Services;
using Module = Autofac.Module;

namespace WT.OpenIddict.WebApi.AutoFac;

public class AutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        var applicationAppAssembly = Assembly.Load("WT.OpenIddict.Application");
        var applicationContractsAppAssembly = Assembly.Load("WT.OpenIddict.Application.Contracts");
        var domainAppAssembly = Assembly.Load("WT.OpenIddict.Domain");
        var domainSharedAppAssembly = Assembly.Load("WT.OpenIddict.Domain.Shared");
        var repositoryAssembly = Assembly.Load("WT.OpenIddict.Repository");
        var assemblies = Assembly.GetExecutingAssembly();
        var allAssenblies = new[]
        {
            assemblies, applicationAppAssembly, applicationContractsAppAssembly, domainAppAssembly,
            domainSharedAppAssembly, repositoryAssembly
        }.Select(a => a).ToArray();

        // 统一使用 InstancePerLifetimeScope
        builder.RegisterType<OpenIddictDbContext>()
            .InstancePerLifetimeScope();

        builder.RegisterGeneric(typeof(BaseRepository<,>))
            .As(typeof(IRepository<,>))
            .InstancePerLifetimeScope();


        builder.RegisterType<HttpContextAccessor>()
            .As<IHttpContextAccessor>()
            .InstancePerLifetimeScope();

        // 注册所有名称以 "AppService" 结尾的公共类，并将它们注册为它们实现的所有接口
        builder.RegisterAssemblyTypes(allAssenblies)
            .Where(c => c.Name.EndsWith("AppService"))
            .PublicOnly()
            .Where(cc => cc.IsClass)
            .AsImplementedInterfaces()
            .InstancePerLifetimeScope();

        // 注册名称不以"AppService" 结尾的公共类，并将它们注册为自身类型
        builder.RegisterAssemblyTypes(allAssenblies)
            .Where(c => !c.Name.EndsWith("AppService"))
            .PublicOnly()
            .Where(cc => cc.IsClass)
            .AsSelf()
            .InstancePerLifetimeScope();

        // 注册所有实现了 ITransientDependency 接口的具体类为瞬态服务
        builder.RegisterAssemblyTypes(allAssenblies)
            .Where(t => typeof(ITransientDependency).IsAssignableFrom(t) && t.IsClass)
            .As<ITransientDependency>()
            .InstancePerDependency();

        // 注册所有 IDomainService 实现类，并同时注册它们的直接接口
        builder.RegisterAssemblyTypes(allAssenblies)
            .Where(t => typeof(IDomainService).IsAssignableFrom(t) && t.IsClass)
            .AsImplementedInterfaces() // 这会注册类实现的所有接口
            .InstancePerDependency();

        // 注册所有实现了 ISingletonDependency 接口的具体类为单例服务
        builder.RegisterAssemblyTypes(allAssenblies)
            .Where(t => typeof(ISingletonDependency).IsAssignableFrom(t) && t.IsClass)
            .As<ISingletonDependency>()
            .SingleInstance();

        // 注册所有实现了 IScopeDependency 接口的具体类为作用域服务
        builder.RegisterAssemblyTypes(allAssenblies)
            .Where(t => typeof(IScopeDependency).IsAssignableFrom(t) && t.IsClass)
            .As<IScopeDependency>()
            .InstancePerLifetimeScope();

        // 对自定义切面的暴露服务实现做注入
        var serviceTypes = applicationAppAssembly.GetTypes()
            .Where(t => t.GetCustomAttributes(typeof(ExposeServiceAtrribute), false).Any())
            .SelectMany(t =>
                ((ExposeServiceAtrribute)t.GetCustomAttribute(typeof(ExposeServiceAtrribute))).ServiceTypes)
            .Distinct();

        foreach (var serviceType in serviceTypes)
        {
            var implementingTypes = applicationAppAssembly.GetTypes()
                .Where(t => t.GetInterfaces().Contains(serviceType))
                .Where(t => t.GetCustomAttributes(typeof(ExposeServiceAtrribute), false).Any());

            foreach (var implementingType in implementingTypes)
                builder.RegisterType(implementingType)
                    .As(serviceType)
                    .InstancePerLifetimeScope();
        }
    }
}